import requests
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry
from typing import Dict, Optional, Any, Union

def create_session_with_retries(
    retries: int = 3,
    backoff_factor: float = 1,
    status_forcelist: tuple = (500, 502, 503, 504)
) -> requests.Session:
    """
    创建带有重试机制的会话
    
    参数:
        retries: 最大重试次数
        backoff_factor: 重试间隔因子
        status_forcelist: 触发重试的HTTP状态码
        
    返回:
        requests.Session: 配置好的会话对象
    """
    session = requests.Session()
    retry = Retry(
        total=retries,
        backoff_factor=backoff_factor,
        status_forcelist=status_forcelist,
        allowed_methods=frozenset(['GET', 'POST', 'PUT', 'DELETE'])  # 允许重试的方法
    )
    adapter = HTTPAdapter(max_retries=retry)
    session.mount('http://', adapter)
    session.mount('https://', adapter)
    return session

def send_json_request(
    url: str,
    payload: Dict[str, Any],
    headers: Optional[Dict[str, str]] = None,
    method: str = 'POST',
    timeout: tuple = (3.05, 27),
    retries: int = 3,
    return_response: bool = False,
    verify_ssl: bool = True
) -> Dict[str, Union[bool, str, int, dict]]:
    """
    发送JSON请求的封装函数
    
    参数:
        url: 请求URL
        payload: 要发送的JSON数据
        headers: 请求头 (可选)
        method: HTTP方法 (POST/GET/PUT/DELETE)
        timeout: (连接超时, 读取超时) 秒
        retries: 重试次数
        return_response: 是否返回完整的响应数据
        verify_ssl: 是否验证SSL证书
        
    返回:
        包含请求结果的字典:
        {
            "success": bool,        # 请求是否成功
            "status_code": int,      # HTTP状态码 (如果可用)
            "data": dict,           # 响应数据 (JSON解析后)
            "text": str,            # 原始响应文本
            "error": str,            # 错误信息 (如果失败)
            "response": requests.Response  # 完整响应对象 (如果return_response=True)
        }
    """
    # 设置默认请求头
    default_headers = {
        'Content-Type': 'application/json',
        'Accept': 'application/json'
    }
    if headers:
        default_headers.update(headers)
    
    result = {
        'success': False,
        'status_code': None,
        'data': None,
        'text': None,
        'error': None
    }
    
    try:
        with create_session_with_retries(retries=retries) as session:
            # 根据方法发送请求
            if method.upper() == 'GET':
                response = session.get(
                    url,
                    params=payload,  # GET请求使用params
                    headers=default_headers,
                    timeout=timeout,
                    verify=verify_ssl
                )
            else:
                response = session.request(
                    method.upper(),
                    url,
                    json=payload,
                    headers=default_headers,
                    timeout=timeout,
                    verify=verify_ssl
                )
            
            # 记录响应信息
            result['status_code'] = response.status_code
            result['text'] = response.text
            
            # 尝试解析JSON响应
            try:
                result['data'] = response.json()
            except ValueError:
                pass  # 非JSON响应
            
            # 检查HTTP错误状态
            response.raise_for_status()
            
            # 请求成功
            result['success'] = True
            
            # 如果需要返回完整响应对象
            if return_response:
                result['response'] = response
    
    except requests.exceptions.HTTPError as http_err:
        result['error'] = f"HTTP错误 ({http_err.response.status_code}): {str(http_err)}"
        if hasattr(http_err, 'response'):
            result['status_code'] = http_err.response.status_code
            try:
                error_data = http_err.response.json()
                result['data'] = error_data
                result['error'] = error_data.get('message', result['error'])
            except ValueError:
                pass
    
    except requests.exceptions.RequestException as req_err:
        result['error'] = f"请求错误: {str(req_err)}"
    
    except Exception as err:
        result['error'] = f"未知错误: {str(err)}"
    
    return result